// Copyright (c) 2011, Jerzy Chalupski
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Jerzy Chalupski nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL JERZY CHALUPSKI BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef ENGINE_H
#define ENGINE_H

#include <QObject>
#include <QSettings>
#include <QTimer>
#include <QVector>
#include <QStringList>

class Engine : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int tick READ tick WRITE setTick NOTIFY tickChanged)
    Q_PROPERTY(int score READ score WRITE setScore NOTIFY scoreChanged)
    Q_PROPERTY(int eggsState READ eggsState NOTIFY eggsStateChanged)
    Q_PROPERTY(int brokenEggs READ brokenEggs WRITE setBrokenEggs NOTIFY brokenEggsChanged)
    Q_PROPERTY(bool gameStarted READ gameStarted WRITE setGameStarted NOTIFY gameStartedChanged)
    Q_PROPERTY(int wolfPosition READ wolfPosition WRITE setWolfPosition NOTIFY wolfPositionChanged)
    Q_PROPERTY(int brokenEggPosition READ brokenEggPosition WRITE setBrokenEggPosition NOTIFY brokenEggPositionChanged)
    Q_PROPERTY(bool displayBrokenEgg READ displayBrokenEgg WRITE setDisplayBrokenEgg NOTIFY displayBrokenEggChanged)
    Q_PROPERTY(bool displayChicken READ displayChicken WRITE setDisplayChicken NOTIFY displayChickenChanged)
    Q_PROPERTY(bool rabbitVisibility READ rabbitVisibility WRITE setRabbitVisibility NOTIFY rabbitVisibilityChanged)
    Q_PROPERTY(bool displayBellAnimation READ displayBellAnimation WRITE setDisplayBellAnimation NOTIFY displayBellAnimationChanged)

    enum Action {
        MoveEggZero,
        MoveEggOne,
        MoveEggTwo,
        MoveEggThree,
        DoNothing,
        GenerateNewEgg
    };

public:
    explicit Engine(QObject *parent = 0);

public: // property getters and setters
    int tick() const;
    void setTick(int value);

    int score() const;
    void setScore(int value);

    int eggsState() const;

    int brokenEggs() const;
    void setBrokenEggs(int value);

    bool gameStarted() const;
    void setGameStarted(bool value);

    int wolfPosition() const;
    void setWolfPosition(int newPosition);

    int brokenEggPosition() const;
    void setBrokenEggPosition(int value);

    bool displayBrokenEgg() const;
    void setDisplayBrokenEgg(bool value);

    bool displayChicken() const;
    void setDisplayChicken(bool value);

    bool rabbitVisibility() const;
    void setRabbitVisibility(bool value);

    bool displayBellAnimation() const;
    void setDisplayBellAnimation(bool value);

private:
    int highscore() const;

private slots:
    void startGame();
    void gameHeartbeat();
    void saveHighscore();
    void showHighscore();
    void clearEggRows();
    void adjustHeartBeat();

    void decreaseLife();
    void randomizeRabbit();
    void levelUp();

signals: // property notify signals
    void tickChanged(int value);
    void scoreChanged(int value);
    void eggsStateChanged();
    void brokenEggsChanged(int value);
    void gameStartedChanged(bool value);
    void wolfPositionChanged(int value);
    void brokenEggPositionChanged(int value);
    void displayBrokenEggChanged(bool value);
    void displayChickenChanged(bool value);
    void rabbitVisibilityChanged(bool value);
    void displayBellAnimationChanged(bool value);

signals: // state change signals
    void backToIdle();
    void newGameClicked();
    void gameOver();
    void lifeLossAnimationFinished();
    void scoreThresholdReached();
    void bellAnimationFinished();

private: // property data
    int mTick;
    int mScore;
    int mBrokenEggs;
    bool mGameStarted;
    int mWolfPosition;
    int mBrokenEggPosition;
    bool mDisplayBrokenEgg;
    bool mDisplayChicken;
    bool mRabbitVisibility;
    bool mDisplayBellAnimation;
    QVector<int> mEggSlots;

private:
    QTimer mHeartbeat;

    QVector<Action> mActions;
    int mCurrentAction;

    QSettings mSettings;
};

#endif // ENGINE_H
